home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / TPTUTR~1.ZIP / PASCAL12.TXT < prev    next >
Text File  |  1996-03-21  |  13KB  |  403 lines

  1.                        Turbo Pascal for DOS Tutorial
  2.                             by Glenn Grotzinger
  3.                         Part 12: Stacks and Queues
  4.                  copyright(c) 1995-96 by Glenn Grotzinger
  5.  
  6. Solution to part 11's problem....
  7.  
  8. program part11; uses dos;
  9.  
  10.   { Lists files and data in a ZIP file. }
  11.  
  12.   type
  13.     ziplocfileheader = record
  14.       zipver: integer;
  15.       bitfield: word;
  16.       compmethod: integer;
  17.       packtime: longint;
  18.       crc32: longint;
  19.       compsize: longint;
  20.       uncompsize: longint;
  21.       filelen: integer;
  22.       xtralen: integer;
  23.     end;
  24.  
  25.     zipcds = record
  26.       ver: byte;
  27.       hostos: byte;
  28.       verxtr: byte;
  29.       targos: byte;
  30.       bitfield: word;
  31.       compmethod: integer;
  32.       packtime: longint;
  33.       crc32: longint;
  34.       compsize: longint;
  35.       uncompsize: longint;
  36.       filelen: integer;
  37.       xtralen: integer;
  38.       comtlen: integer;
  39.       disknum: integer;
  40.       intattr: integer;
  41.       extattr: longint;
  42.       roffset: longint;
  43.     end;
  44.  
  45.     endcdsheader = record
  46.       numdisk: integer;
  47.       numdiska: integer;
  48.       numfiles: integer;
  49.       entries: integer;
  50.       size: longint;
  51.       ofs: longint;
  52.       comtlength: integer;
  53.     end;
  54.  
  55.   var
  56.     zipfile: file;
  57.     outfile: text;
  58.     locfile: ziplocfileheader;
  59.     dirstr: zipcds;
  60.     endcds: endcdsheader;
  61.     filechar: char;
  62.     filelength: array[1..20] of char;
  63.     id: array[1..4] of char;
  64.     i: integer;
  65.     totsize, compsize, uncompsize: longint;
  66.     param1, param2: string;
  67.  
  68.   { Example structure of a ZIP file.
  69.       localheader1
  70.       loccompresseddata1
  71.       localheader2
  72.       loccompresseddata2
  73.       centraldirectorystructure1
  74.       centraldirectorystructure2
  75.       endofcentraldirectorystructure }
  76.  
  77.   procedure readzip;
  78.  
  79.     { ZIP is a random data binary file.  We read the ID to check it, then
  80.       differentiate it from there.  We also devise a test of whether the
  81.       "ZIP file" is a valid ZIP file here. }
  82.  
  83.     begin
  84.       blockread(zipfile, id, sizeof(id));
  85.       totsize := totsize + 4; { totsize is a seek index }
  86.       if (id[1] <> 'P') and (id[2] <> 'K') then
  87.         begin
  88.           writeln('Corrupted ZIP file, or not a ZIP file.');
  89.           halt(1);
  90.         end;
  91.       case id[3] of
  92.         #05: begin
  93.                blockread(zipfile, endcds, sizeof(endcds));
  94.                totsize := totsize + sizeof(endcds);
  95.              end;
  96.         #03: begin
  97.                blockread(zipfile, locfile, sizeof(locfile));
  98.                totsize := totsize + sizeof(locfile);
  99.              end;
  100.         #01: begin
  101.                blockread(zipfile, dirstr, sizeof(dirstr));
  102.                totsize := totsize + sizeof(dirstr);
  103.              end;
  104.       end;
  105.     end;
  106.  
  107.   function zero(int: integer):string;
  108.     {places zero on the beginning of a number if it's < 10 }
  109.     var
  110.       strng: string;
  111.       numerr: integer;
  112.     begin
  113.       str(int, strng);
  114.       if int < 10 then
  115.         strng := '0' + strng;
  116.       zero := strng;
  117.     end;
  118.  
  119.   function strip(str: string):string;
  120.  
  121.     { removes null characters from random-read filename }
  122.  
  123.     var
  124.       tstr: string;
  125.       i: integer;
  126.     begin
  127.       tstr := '';
  128.       for i := 1 to length(str) do
  129.         if str[i] <> #0 then
  130.           tstr := tstr + str[i];
  131.       strip := tstr;
  132.     end;
  133.  
  134.   function exist(filename: string):boolean;
  135.     { file existence test }
  136.     var
  137.       thefile: text;
  138.     begin
  139.       assign(thefile, filename);
  140.       {$I-}reset(thefile);{$I+}
  141.       if IOResult <> 0 then
  142.         exist := false
  143.       else
  144.         begin
  145.           exist := true;
  146.           close(thefile);
  147.         end;
  148.     end;
  149.  
  150.   procedure header(filename: string);
  151.     { writes header of data }
  152.     var
  153.       s: string;
  154.     begin
  155.       writeln(outfile, 'Files contained in ':41, filename);
  156.       writeln(outfile);
  157.       writeln(outfile, 'NAME', 'COMP-SIZE':21, 'DATE':9,'TIME':12,
  158.               'UNCOMP-SIZE':15, 'COMP-METHOD':13);
  159.       fillchar(s, 75, '-');
  160.       { fillchar fills a set of contiguous bytes of any type defined by
  161.         the position s is in, for x number of spaces (75), with a char-
  162.         acter represented by - }
  163.       s[0] := #74;  { set length byte }
  164.       writeln(outfile, s);
  165.     end;
  166.  
  167.   procedure footer(compsize, uncompsize: longint);
  168.     { write footer of data }
  169.     var
  170.       s: string;
  171.     begin
  172.       fillchar(s, 75, '-');
  173.       s[0] := #74;
  174.       writeln(outfile, s);
  175.       writeln(outfile, compsize:22, uncompsize:34);
  176.       writeln(outfile);
  177.       writeln(outfile, endcds.numfiles, ' files; Effective compression',
  178.                        ' ratio: ', (compsize / uncompsize)*100 :0:1, '%');
  179.     end;
  180.  
  181.   procedure writehelp;
  182.     { help for incorrect usage }
  183.     begin
  184.       writeln('ZIPLIST <zipfile> <datafile>');
  185.       halt(1);
  186.     end;
  187.  
  188.   procedure writedata(locfile: ziplocfileheader);
  189.     var
  190.       dt: datetime;
  191.     begin
  192.       unpacktime(locfile.packtime, dt);
  193.       { this handles the MS-DOS time format }
  194.       writeln(outfile, strip(filelength):12, locfile.compsize:10,
  195.       zero(dt.month):7,'-',zero(dt.day),'-',dt.year,
  196.       zero(dt.hour):6,':', zero(dt.min),
  197.       locfile.uncompsize:10, locfile.compmethod:12);
  198.     end;
  199.  
  200.   begin
  201.     if paramcount <> 2 then  { incorrect parameters? }
  202.       writehelp;
  203.     totsize := 0;compsize := 0;uncompsize := 0;
  204.     param1 := paramstr(1);
  205.     param2 := paramstr(2);
  206.     assign(zipfile, param1);
  207.     if exist(param1) = false then
  208.       begin
  209.         writeln(param1, ' does not exist!');
  210.         halt(1);
  211.       end;
  212.     reset(zipfile, 1);
  213.     assign(outfile, param2);
  214.     rewrite(outfile);
  215.  
  216.     header(param1);
  217.     readzip;
  218.  
  219.     while id[3] = #03 do
  220.      { process local file headers and compressed data }
  221.       begin
  222.         blockread(zipfile, filelength, locfile.filelen);
  223.         compsize := compsize + locfile.compsize;
  224.         uncompsize := uncompsize + locfile.uncompsize;
  225.         writedata(locfile);
  226.         totsize := totsize + locfile.filelen;
  227.         totsize := totsize + locfile.xtralen;
  228.         fillchar(filelength, sizeof(filelength),#0);
  229.         seek(zipfile, totsize);
  230.         totsize := totsize + locfile.compsize;
  231.         seek(zipfile, totsize);
  232.         readzip;
  233.       end;
  234.  
  235.     while id[3] = #01 do
  236.       { process central directory structure }
  237.       begin
  238.         totsize := totsize + dirstr.filelen;
  239.         seek(zipfile, totsize);
  240.         totsize := totsize + dirstr.xtralen;
  241.         seek(zipfile, totsize);
  242.         readzip;
  243.       end;
  244.  
  245.     footer(compsize, uncompsize);
  246.  
  247.     writeln(outfile);
  248.  
  249.     { handle ZIP comment }
  250.     if endcds.comtlength = 0 then
  251.       writeln(outfile, 'No comment in ZIP file.')
  252.     else
  253.       for i := 1 to endcds.comtlength do
  254.         begin
  255.           blockread(zipfile, filechar, sizeof(filechar));
  256.           write(outfile, filechar);
  257.         end;
  258.     
  259.     close(zipfile);
  260.     close(outfile);
  261.   end.
  262.  
  263. Hello.  Basically, we are dealing in this part with specialized types of
  264. data structures called stacks and queues.
  265.  
  266. Stacks
  267. ======
  268. A stack is best analagous to a stack of papers on a desk, only able to
  269. either place a sheet on the top of the stack, or take a sheet off the
  270. top of the stack.  It is generally defined as a record format, which
  271. can take on the following:
  272.  
  273. stack = record
  274.   elements: array[1..maxstacksize] of <whatever>;
  275.   capacity: integer; {range of 0..maxstacksize}
  276. end;
  277.  
  278. It is best described as a last in/ first out data structure, much like the
  279. sheet of paper analogy.  The elements array holds whatever information
  280. we need, while capacity tells us how many elements are still in the array.
  281.  
  282. The best description I can use for this and queues is that it's a limited
  283. defined access structure.
  284.  
  285. I will now describe the basic actions of working with stacks.  The best
  286. way to think about coding this is to use the stack of paper as a view-
  287. point, and using the sample stack record above.
  288.  
  289. To initialize or effectively kill a stack currently in usage is to set
  290. capacity to 0.  We can do this, because all work with a stack ultimately
  291. comes down to usage of capacity as an index.  If we have 0 sheets of paper
  292. on an imaginary stack, essentially, the stack is empty.
  293.  
  294. Now, let's add a sheet of paper to our imaginary stack.  We recognize that
  295. there is one more sheet of paper on the stack now.  Then we have to place
  296. that sheet on the stack...also, we have to keep in mind if we have hit our
  297. arbitrarily set limit of sheets on the stack, and notify of such thing.
  298.  
  299. What now, if we have to remove the sheet of paper from our imaginary stack
  300. of paper?  We would need to check if we had a sheet of paper to remove.
  301. Then after that, we would need to pull the sheet off of the stack, then
  302. recognize that we removed the sheet.
  303.  
  304. How do we recognize if we have a full stack or an empty stack?  Look at the
  305. value of capacity.  If it's 0, then it's empty.  If it's the value for the
  306. maximum capacity of the stack we decide, then we know it's full.
  307.  
  308. Basically, in the last four paragraphs, I have, in discussing the actions
  309. of working with stacks, have given you all the pseudocode you need to
  310. be able to come up with the code to work with a stack.
  311.  
  312. It is basically good to develop all of these components as procedures.
  313. If you come across a problem where a last in, first out solution is
  314. needed, a stack may be the proper way to go.
  315.  
  316. Queues
  317. ======
  318. A queue is set up much like a line at the local shop to pay the merchant
  319. at the cash register.  The first element in is the first element out.
  320. Much like a stack, a queue may be defined as a record format.
  321.  
  322. queue = record
  323.   elements: array[1..maxqueuesize] of <whatever>;
  324.   front, back: integer;
  325.   count: integer;
  326. end;
  327.  
  328. Notice that the differences we see here, are that to take from the front
  329. of the so called line we need to know where the front is in the order.
  330. The same idea occurs with the back.  We need to know where the back is
  331. in the array.  Count just helps us in knowing how many values we currently
  332. have in the queue.
  333.  
  334. To start up a queue, basically, we need to start the front at 1, the rear
  335. at the maximum size, and count at zero.
  336.  
  337. To check whether it's full or  empty is basically set through count.  Check
  338. count to be zero for a queue to be empty and maxsize for a queue to be full.
  339.  
  340. One sticky mess comes up when we try to add an element to the back of the
  341. line.  How do we keep track of things?  We increment the back unless it's
  342. maxqueuesize, then we set it to 1, essentially, to continue reusing the
  343. array storage as a loop....
  344.  
  345. To add to the back of the line, we do like we did with the stack.  We add
  346. the element to the back, then we increment the back count as described
  347. above.
  348.  
  349. To take from the front of the line, we pull the element from the front of
  350. the queue, and then increment the front count as described above.
  351.  
  352. Basically, the effect we are getting is much like a message scrolling
  353. across a surface, like you may have seen on your television, and at
  354. Times Square in NY (on several movies).
  355.  
  356. Conclusion
  357. ==========
  358. Both of these data storage schemes work beautifully, when you have a lot of
  359. data to deal with that can be passed through quickly, but needs to be
  360. released at other times...beyond that, at this point, I can't think of
  361. anything that can be done by only using a stack or a queue, so my
  362. suggestion for practice is to attempt coding each of these specialized
  363. data types to do simple things.
  364.  
  365.  
  366. Practice Programming Problem(s) #12
  367. ===================================
  368. Here are a couple of things for this one.
  369.  
  370. 1) Reverse a string of text inputted from the screen (not necessarily
  371. a string) of a maximum of 500 characters, and output the text back to
  372. the screen.
  373.  
  374. Sample
  375. ------
  376. Enter a string: AbCdE
  377.  
  378. Your string reversed is: EdCbA
  379.  
  380. 2) Use a queue to store a maximum set of numbers that is 50 numbers long.
  381. These numbers will come from a series of randomly generated numbers by your
  382. program.  The random numbers you will generate are from 1..1000, and
  383. the ones that are from 1..50 will be written out to the screen when the
  384. queue is filled up with those numbers.  Write the numbers in the queue out
  385. in 5 rows of 10, and at the bottom, write out the total number of random
  386. numbers you had to go through to get those 50 numbers in the proper range.
  387.  
  388. Sample
  389. ------
  390. 23 23 11 22 33 1 9 12 23 11
  391. 23 3 11 22 33 11 9 12 23 11
  392. 23 23 11 22 33 11 9 12 23 11
  393. 23 29 11 2 33 11 9 12 23 11
  394. 23 23 11 22 33 11 9 50 23 11
  395.  
  396. 987 numbers were generated from 1-1000 to get the 50 numbers from 1-50.
  397.  
  398. Next Time
  399. =========
  400. Recursion. (n) See Recursion. :>
  401.  
  402. Any comments?  Write ggrotz@2sprint.net.
  403.